{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Build a machine learning workflow using Step Functions and SageMaker\n",
    "\n",
    "1. [Introduction](#Introduction)\n",
    "1. [Setup](#Setup)\n",
    "1. [Build a machine learning workflow](#Build-a-machine-learning-workflow)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Introduction\n",
    "\n",
    "This notebook describes using the AWS Step Functions Data Science SDK to create and manage workflows. The Step Functions SDK is an open source library that allows data scientists to easily create and execute machine learning workflows using AWS Step Functions and Amazon SageMaker. For more information, see the following.\n",
    "* [AWS Step Functions](https://aws.amazon.com/step-functions/)\n",
    "* [AWS Step Functions Developer Guide](https://docs.aws.amazon.com/step-functions/latest/dg/welcome.html)\n",
    "* [AWS Step Functions Data Science SDK](https://aws-step-functions-data-science-sdk.readthedocs.io)\n",
    "\n",
    "In this notebook we will use the SDK to create steps, link them together to create a workflow, and execute the workflow in AWS Step Functions. The first tutorial shows how to create an ML pipeline workflow, and the second shows how to run multiple experiments in parallel."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Requirement already up-to-date: stepfunctions in /home/ec2-user/anaconda3/envs/python3/lib/python3.6/site-packages (1.0.0.3)\n",
      "Requirement not upgraded as not directly required: boto3>=1.9.213 in /home/ec2-user/anaconda3/envs/python3/lib/python3.6/site-packages (from stepfunctions) (1.10.19)\n",
      "Requirement not upgraded as not directly required: sagemaker>=1.42.8 in /home/ec2-user/anaconda3/envs/python3/lib/python3.6/site-packages (from stepfunctions) (1.45.0.dev0)\n",
      "Requirement not upgraded as not directly required: pyyaml in /home/ec2-user/anaconda3/envs/python3/lib/python3.6/site-packages (from stepfunctions) (3.12)\n",
      "Requirement not upgraded as not directly required: jmespath<1.0.0,>=0.7.1 in /home/ec2-user/anaconda3/envs/python3/lib/python3.6/site-packages (from boto3>=1.9.213->stepfunctions) (0.9.4)\n",
      "Requirement not upgraded as not directly required: botocore<1.14.0,>=1.13.19 in /home/ec2-user/anaconda3/envs/python3/lib/python3.6/site-packages (from boto3>=1.9.213->stepfunctions) (1.13.19)\n",
      "Requirement not upgraded as not directly required: s3transfer<0.3.0,>=0.2.0 in /home/ec2-user/anaconda3/envs/python3/lib/python3.6/site-packages (from boto3>=1.9.213->stepfunctions) (0.2.1)\n",
      "Requirement not upgraded as not directly required: protobuf>=3.1 in /home/ec2-user/anaconda3/envs/python3/lib/python3.6/site-packages (from sagemaker>=1.42.8->stepfunctions) (3.6.1)\n",
      "Requirement not upgraded as not directly required: protobuf3-to-dict>=0.1.5 in /home/ec2-user/anaconda3/envs/python3/lib/python3.6/site-packages (from sagemaker>=1.42.8->stepfunctions) (0.1.5)\n",
      "Requirement not upgraded as not directly required: scipy>=0.19.0 in /home/ec2-user/anaconda3/envs/python3/lib/python3.6/site-packages (from sagemaker>=1.42.8->stepfunctions) (1.1.0)\n",
      "Requirement not upgraded as not directly required: smdebug-rulesconfig==0.1.2 in /home/ec2-user/anaconda3/envs/python3/lib/python3.6/site-packages (from sagemaker>=1.42.8->stepfunctions) (0.1.2)\n",
      "Requirement not upgraded as not directly required: requests<2.21,>=2.20.0 in /home/ec2-user/anaconda3/envs/python3/lib/python3.6/site-packages (from sagemaker>=1.42.8->stepfunctions) (2.20.0)\n",
      "Requirement not upgraded as not directly required: numpy>=1.9.0 in /home/ec2-user/anaconda3/envs/python3/lib/python3.6/site-packages (from sagemaker>=1.42.8->stepfunctions) (1.14.3)\n",
      "Requirement not upgraded as not directly required: urllib3<1.26,>=1.20; python_version >= \"3.4\" in /home/ec2-user/anaconda3/envs/python3/lib/python3.6/site-packages (from botocore<1.14.0,>=1.13.19->boto3>=1.9.213->stepfunctions) (1.23)\n",
      "Requirement not upgraded as not directly required: python-dateutil<2.8.1,>=2.1; python_version >= \"2.7\" in /home/ec2-user/anaconda3/envs/python3/lib/python3.6/site-packages (from botocore<1.14.0,>=1.13.19->boto3>=1.9.213->stepfunctions) (2.7.3)\n",
      "Requirement not upgraded as not directly required: docutils<0.16,>=0.10 in /home/ec2-user/anaconda3/envs/python3/lib/python3.6/site-packages (from botocore<1.14.0,>=1.13.19->boto3>=1.9.213->stepfunctions) (0.14)\n",
      "Requirement not upgraded as not directly required: six>=1.9 in /home/ec2-user/anaconda3/envs/python3/lib/python3.6/site-packages (from protobuf>=3.1->sagemaker>=1.42.8->stepfunctions) (1.11.0)\n",
      "Requirement not upgraded as not directly required: setuptools in /home/ec2-user/anaconda3/envs/python3/lib/python3.6/site-packages (from protobuf>=3.1->sagemaker>=1.42.8->stepfunctions) (39.1.0)\n",
      "Requirement not upgraded as not directly required: idna<2.8,>=2.5 in /home/ec2-user/anaconda3/envs/python3/lib/python3.6/site-packages (from requests<2.21,>=2.20.0->sagemaker>=1.42.8->stepfunctions) (2.6)\n",
      "Requirement not upgraded as not directly required: chardet<3.1.0,>=3.0.2 in /home/ec2-user/anaconda3/envs/python3/lib/python3.6/site-packages (from requests<2.21,>=2.20.0->sagemaker>=1.42.8->stepfunctions) (3.0.4)\n",
      "Requirement not upgraded as not directly required: certifi>=2017.4.17 in /home/ec2-user/anaconda3/envs/python3/lib/python3.6/site-packages (from requests<2.21,>=2.20.0->sagemaker>=1.42.8->stepfunctions) (2019.9.11)\n",
      "\u001b[33mYou are using pip version 10.0.1, however version 19.3.1 is available.\n",
      "You should consider upgrading via the 'pip install --upgrade pip' command.\u001b[0m\n"
     ]
    }
   ],
   "source": [
    "import sys\n",
    "!{sys.executable} -m pip install --upgrade stepfunctions"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Setup\n",
    "\n",
    "### Add a policy to your SageMaker role in IAM\n",
    "\n",
    "**If you are running this notebook on an Amazon SageMaker notebook instance**, the IAM role assumed by your notebook instance needs permission to create and run workflows in AWS Step Functions. To provide this permission to the role, do the following.\n",
    "\n",
    "1. Open the Amazon [SageMaker console](https://console.aws.amazon.com/sagemaker/). \n",
    "2. Select **Notebook instances** and choose the name of your notebook instance\n",
    "3. Under **Permissions and encryption** select the role ARN to view the role on the IAM console\n",
    "4. Choose **Attach policies** and search for `AWSStepFunctionsFullAccess`.\n",
    "5. Select the check box next to `AWSStepFunctionsFullAccess` and choose **Attach policy**\n",
    "\n",
    "If you are running this notebook in a local environment, the SDK will use your configured AWS CLI configuration. For more information, see [Configuring the AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-configure.html).\n",
    "\n",
    "Next, create an execution role in IAM for Step Functions. \n",
    "\n",
    "### Create an execution role for Step Functions\n",
    "\n",
    "You need an execution role so that you can create and execute workflows in Step Functions.\n",
    "\n",
    "1. Go to the [IAM console](https://console.aws.amazon.com/iam/)\n",
    "2. Select **Roles** and then **Create role**.\n",
    "3. Under **Choose the service that will use this role** select **Step Functions**\n",
    "4. Choose **Next** until you can enter a **Role name**\n",
    "5. Enter a name such as `StepFunctionsWorkflowExecutionRole` and then select **Create role**\n",
    "\n",
    "\n",
    "Attach a policy to the role you created. The following steps attach a policy that provides full access to Step Functions, however as a good practice you should only provide access to the resources you need.  \n",
    "\n",
    "1. Under the **Permissions** tab, click **Add inline policy**\n",
    "2. Enter the following in the **JSON** tab\n",
    "\n",
    "```json\n",
    "{\n",
    "    \"Version\": \"2012-10-17\",\n",
    "    \"Statement\": [\n",
    "        {\n",
    "            \"Effect\": \"Allow\",\n",
    "            \"Action\": [\n",
    "                \"sagemaker:CreateTransformJob\",\n",
    "                \"sagemaker:DescribeTransformJob\",\n",
    "                \"sagemaker:StopTransformJob\",\n",
    "                \"sagemaker:CreateTrainingJob\",\n",
    "                \"sagemaker:DescribeTrainingJob\",\n",
    "                \"sagemaker:StopTrainingJob\",\n",
    "                \"sagemaker:CreateHyperParameterTuningJob\",\n",
    "                \"sagemaker:DescribeHyperParameterTuningJob\",\n",
    "                \"sagemaker:StopHyperParameterTuningJob\",\n",
    "                \"sagemaker:CreateModel\",\n",
    "                \"sagemaker:CreateEndpointConfig\",\n",
    "                \"sagemaker:CreateEndpoint\",\n",
    "                \"sagemaker:DeleteEndpointConfig\",\n",
    "                \"sagemaker:DeleteEndpoint\",\n",
    "                \"sagemaker:UpdateEndpoint\",\n",
    "                \"sagemaker:ListTags\",\n",
    "                \"lambda:InvokeFunction\",\n",
    "                \"sqs:SendMessage\",\n",
    "                \"sns:Publish\",\n",
    "                \"ecs:RunTask\",\n",
    "                \"ecs:StopTask\",\n",
    "                \"ecs:DescribeTasks\",\n",
    "                \"dynamodb:GetItem\",\n",
    "                \"dynamodb:PutItem\",\n",
    "                \"dynamodb:UpdateItem\",\n",
    "                \"dynamodb:DeleteItem\",\n",
    "                \"batch:SubmitJob\",\n",
    "                \"batch:DescribeJobs\",\n",
    "                \"batch:TerminateJob\",\n",
    "                \"glue:StartJobRun\",\n",
    "                \"glue:GetJobRun\",\n",
    "                \"glue:GetJobRuns\",\n",
    "                \"glue:BatchStopJobRun\"\n",
    "            ],\n",
    "            \"Resource\": \"*\"\n",
    "        },\n",
    "        {\n",
    "            \"Effect\": \"Allow\",\n",
    "            \"Action\": [\n",
    "                \"iam:PassRole\"\n",
    "            ],\n",
    "            \"Resource\": \"*\",\n",
    "            \"Condition\": {\n",
    "                \"StringEquals\": {\n",
    "                    \"iam:PassedToService\": \"sagemaker.amazonaws.com\"\n",
    "                }\n",
    "            }\n",
    "        },\n",
    "        {\n",
    "            \"Effect\": \"Allow\",\n",
    "            \"Action\": [\n",
    "                \"events:PutTargets\",\n",
    "                \"events:PutRule\",\n",
    "                \"events:DescribeRule\"\n",
    "            ],\n",
    "            \"Resource\": [\n",
    "                \"arn:aws:events:*:*:rule/StepFunctionsGetEventsForSageMakerTrainingJobsRule\",\n",
    "                \"arn:aws:events:*:*:rule/StepFunctionsGetEventsForSageMakerTransformJobsRule\",\n",
    "                \"arn:aws:events:*:*:rule/StepFunctionsGetEventsForSageMakerTuningJobsRule\",\n",
    "                \"arn:aws:events:*:*:rule/StepFunctionsGetEventsForECSTaskRule\",\n",
    "                \"arn:aws:events:*:*:rule/StepFunctionsGetEventsForBatchJobsRule\"\n",
    "            ]\n",
    "        }\n",
    "    ]\n",
    "}\n",
    "```\n",
    "\n",
    "3. Choose **Review policy** and give the policy a name such as `StepFunctionsWorkflowExecutionPolicy`\n",
    "4. Choose **Create policy**. You will be redirected to the details page for the role.\n",
    "5. Copy the **Role ARN** at the top of the **Summary**"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Configure execution roles"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "import sagemaker\n",
    "\n",
    "# SageMaker Execution Role\n",
    "# You can use sagemaker.get_execution_role() if running inside sagemaker's notebook instance\n",
    "sagemaker_execution_role = sagemaker.get_execution_role() #Replace with ARN if not in an AWS SageMaker notebook\n",
    "\n",
    "# paste the StepFunctionsWorkflowExecutionRole ARN from above\n",
    "workflow_execution_role = \"arn:aws:iam::806570384721:role/StepFunctionsExecutionRole\" "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Import the required modules"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "import boto3\n",
    "import sagemaker\n",
    "import time\n",
    "import random\n",
    "import uuid\n",
    "import logging\n",
    "import stepfunctions\n",
    "import io\n",
    "import random\n",
    "\n",
    "from sagemaker.amazon.amazon_estimator import get_image_uri\n",
    "from stepfunctions import steps\n",
    "from stepfunctions.steps import TrainingStep, ModelStep, TransformStep\n",
    "from stepfunctions.inputs import ExecutionInput\n",
    "from stepfunctions.workflow import Workflow\n",
    "from stepfunctions.template import TrainingPipeline\n",
    "from stepfunctions.template.utils import replace_parameters_with_jsonpath\n",
    "\n",
    "session = sagemaker.Session()\n",
    "stepfunctions.set_stream_logger(level=logging.INFO)\n",
    "\n",
    "region = boto3.Session().region_name\n",
    "bucket = session.default_bucket()\n",
    "prefix = 'sagemaker/DEMO-xgboost-regression'\n",
    "bucket_path = 'https://s3-{}.amazonaws.com/{}'.format(region, bucket)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Prepare the dataset\n",
    "\n",
    "The following cell defines utility methods to split a dataset into train, validation, and test datasets. It then defines methods to upload them to an Amazon S3 bucket."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "def data_split(FILE_DATA, FILE_TRAIN, FILE_VALIDATION, FILE_TEST, PERCENT_TRAIN, PERCENT_VALIDATION, PERCENT_TEST):\n",
    "    data = [l for l in open(FILE_DATA, 'r')]\n",
    "    train_file = open(FILE_TRAIN, 'w')\n",
    "    valid_file = open(FILE_VALIDATION, 'w')\n",
    "    tests_file = open(FILE_TEST, 'w')\n",
    "\n",
    "    num_of_data = len(data)\n",
    "    num_train = int((PERCENT_TRAIN/100.0)*num_of_data)\n",
    "    num_valid = int((PERCENT_VALIDATION/100.0)*num_of_data)\n",
    "    num_tests = int((PERCENT_TEST/100.0)*num_of_data)\n",
    "\n",
    "    data_fractions = [num_train, num_valid, num_tests]\n",
    "    split_data = [[],[],[]]\n",
    "\n",
    "    rand_data_ind = 0\n",
    "\n",
    "    for split_ind, fraction in enumerate(data_fractions):\n",
    "        for i in range(fraction):\n",
    "            rand_data_ind = random.randint(0, len(data)-1)\n",
    "            split_data[split_ind].append(data[rand_data_ind])\n",
    "            data.pop(rand_data_ind)\n",
    "\n",
    "    for l in split_data[0]:\n",
    "        train_file.write(l)\n",
    "\n",
    "    for l in split_data[1]:\n",
    "        valid_file.write(l)\n",
    "\n",
    "    for l in split_data[2]:\n",
    "        tests_file.write(l)\n",
    "\n",
    "    train_file.close()\n",
    "    valid_file.close()\n",
    "    tests_file.close()\n",
    "\n",
    "def write_to_s3(fobj, bucket, key):\n",
    "    return boto3.Session(region_name=region).resource('s3').Bucket(bucket).Object(key).upload_fileobj(fobj)\n",
    "\n",
    "def upload_to_s3(bucket, channel, filename):\n",
    "    fobj=open(filename, 'rb')\n",
    "    key = prefix+'/'+channel\n",
    "    url = 's3://{}/{}/{}'.format(bucket, key, filename)\n",
    "    print('Writing to {}'.format(url))\n",
    "    write_to_s3(fobj, bucket, key)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "This notebook uses the XGBoost algorithm to train and host a regression model. We use the [Abalone data](https://www.csie.ntu.edu.tw/~cjlin/libsvmtools/datasets/regression.html) originally from the [UCI data repository](https://archive.ics.uci.edu/ml/datasets/abalone). More details about the original dataset can be found [here](https://archive.ics.uci.edu/ml/machine-learning-databases/abalone/abalone.names).  In the libsvm converted [version](https://www.csie.ntu.edu.tw/~cjlin/libsvmtools/datasets/regression.html), the nominal feature (Male/Female/Infant) has been converted into a real valued feature. Age of abalone is to be predicted from eight physical measurements.  "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Writing to s3://sagemaker-us-east-1-806570384721/sagemaker/DEMO-xgboost-regression/train/abalone.train\n",
      "Writing to s3://sagemaker-us-east-1-806570384721/sagemaker/DEMO-xgboost-regression/validation/abalone.validation\n",
      "Writing to s3://sagemaker-us-east-1-806570384721/sagemaker/DEMO-xgboost-regression/test/abalone.test\n"
     ]
    }
   ],
   "source": [
    "try: #python3\n",
    "    from urllib.request import urlretrieve\n",
    "except: #python2\n",
    "    from urllib import urlretrieve\n",
    "    \n",
    "# Load the dataset\n",
    "FILE_DATA = 'abalone'\n",
    "urlretrieve(\"https://www.csie.ntu.edu.tw/~cjlin/libsvmtools/datasets/regression/abalone\", FILE_DATA)\n",
    "\n",
    "#split the downloaded data into train/test/validation files\n",
    "FILE_TRAIN = 'abalone.train'\n",
    "FILE_VALIDATION = 'abalone.validation'\n",
    "FILE_TEST = 'abalone.test'\n",
    "PERCENT_TRAIN = 70\n",
    "PERCENT_VALIDATION = 15\n",
    "PERCENT_TEST = 15\n",
    "data_split(FILE_DATA, FILE_TRAIN, FILE_VALIDATION, FILE_TEST, PERCENT_TRAIN, PERCENT_VALIDATION, PERCENT_TEST)\n",
    "\n",
    "#upload the files to the S3 bucket\n",
    "upload_to_s3(bucket, 'train', FILE_TRAIN)\n",
    "upload_to_s3(bucket, 'validation', FILE_VALIDATION)\n",
    "upload_to_s3(bucket, 'test', FILE_TEST)\n",
    "\n",
    "train_s3_file = bucket_path + \"/\" + prefix + '/train'\n",
    "validation_s3_file = bucket_path + \"/\" + prefix + '/validation'\n",
    "test_s3_file = bucket_path + \"/\" + prefix + '/test'"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Configure the AWS Sagemaker estimator"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "xgb = sagemaker.estimator.Estimator(\n",
    "    get_image_uri(region, 'xgboost'),\n",
    "    sagemaker_execution_role, \n",
    "    train_instance_count = 1, \n",
    "    train_instance_type = 'ml.m4.4xlarge',\n",
    "    train_volume_size = 5,\n",
    "    output_path = bucket_path + \"/\" + prefix + \"/single-xgboost\",\n",
    "    sagemaker_session = session\n",
    ")\n",
    "\n",
    "xgb.set_hyperparameters(\n",
    "    objective = 'reg:linear',\n",
    "    num_round = 50,\n",
    "    max_depth = 5,\n",
    "    eta = 0.2,\n",
    "    gamme = 4,\n",
    "    min_child_weight = 6,\n",
    "    subsample = 0.7,\n",
    "    silent = 0\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "## Build a machine learning workflow"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<img src=\"img/e2e_pipeline.png\">"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "You can use a workflow to create a machine learning pipeline. The AWS Data Science Workflows SDK provides several AWS SageMaker workflow steps that you can use to construct an ML pipeline. In this tutorial you will use the Train and Transform steps.\n",
    "\n",
    "* [**TrainingStep**](https://aws-step-functions-data-science-sdk.readthedocs.io/en/latest/sagemaker.html#stepfunctions.steps.sagemaker.TrainingStep) - Starts a Sagemaker training job and outputs the model artifacts to S3.\n",
    "* [**ModelStep**](https://aws-step-functions-data-science-sdk.readthedocs.io/en/latest/sagemaker.html#stepfunctions.steps.sagemaker.ModelStep) - Creates a model on SageMaker using the model artifacts from S3.\n",
    "* [**TransformStep**](https://aws-step-functions-data-science-sdk.readthedocs.io/en/latest/sagemaker.html#stepfunctions.steps.sagemaker.TransformStep) - Starts a SageMaker transform job\n",
    "* [**EndpointConfigStep**](https://aws-step-functions-data-science-sdk.readthedocs.io/en/latest/sagemaker.html#stepfunctions.steps.sagemaker.EndpointConfigStep) - Defines an endpoint configuration on SageMaker.\n",
    "* [**EndpointStep**](https://aws-step-functions-data-science-sdk.readthedocs.io/en/latest/sagemaker.html#stepfunctions.steps.sagemaker.EndpointStep) - Deploys the trained model to the configured endpoint."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Define the input schema for a workflow execution\n",
    "\n",
    "The [**ExecutionInput**](https://aws-step-functions-data-science-sdk.readthedocs.io/en/latest/placeholders.html#stepfunctions.inputs.ExecutionInput) API defines the options to dynamically pass information to a workflow at runtime.\n",
    "\n",
    "The following cell defines the fields that must be passed to your workflow when starting an execution.\n",
    "\n",
    "While the workflow is usually static after it is defined, you may want to pass values dynamically that are used by steps in your workflow. To help with this, the SDK provides a way to create placeholders when you define your workflow. These placeholders can be dynamically assigned values when you execute your workflow.\n",
    "\n",
    "ExecutionInput values are accessible to each step of your workflow. You have the ability to define a schema for this placeholder collection, as shown in the cell below. When you execute your workflow the SDK will verify if the dynamic input conforms to the schema you defined."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [],
   "source": [
    "# SageMaker expects unique names for each job, model and endpoint. \n",
    "# If these names are not unique the execution will fail. Pass these\n",
    "# dynamically for each execution using placeholders.\n",
    "execution_input = ExecutionInput(schema={\n",
    "    'JobName': str, \n",
    "    'ModelName': str,\n",
    "    'EndpointName': str\n",
    "})"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Create the training step \n",
    "\n",
    "In the following cell we create the training step and pass the estimator we defined above. See  [TrainingStep](https://aws-step-functions-data-science-sdk.readthedocs.io/en/latest/sagemaker.html#stepfunctions.steps.sagemaker.TrainingStep) in the AWS Step Functions Data Science SDK documentation."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [],
   "source": [
    "training_step = steps.TrainingStep(\n",
    "    state_id='Train Step', \n",
    "    estimator=xgb,\n",
    "    data={\n",
    "        'train': sagemaker.s3_input(train_s3_file, content_type='libsvm'),\n",
    "        'validation': sagemaker.s3_input(validation_s3_file, content_type='libsvm')\n",
    "    },\n",
    "    job_name=execution_input['JobName']  \n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Create the model step \n",
    "\n",
    "In the following cell we define a model step that will create a model in SageMaker using the artifacts created during the TrainingStep. See  [ModelStep](https://aws-step-functions-data-science-sdk.readthedocs.io/en/latest/sagemaker.html#stepfunctions.steps.sagemaker.ModelStep) in the AWS Step Functions Data Science SDK documentation.\n",
    "\n",
    "The model creation step typically follows the training step. The Step Functions SDK provides the [get_expected_model](https://aws-step-functions-data-science-sdk.readthedocs.io/en/latest/sagemaker.html#stepfunctions.steps.sagemaker.TrainingStep.get_expected_model) method in the TrainingStep class to provide a reference for the trained model artifacts. Please note that this method is only useful when the ModelStep directly follows the TrainingStep."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [],
   "source": [
    "model_step = steps.ModelStep(\n",
    "    'Save model',\n",
    "    model=training_step.get_expected_model(),\n",
    "    model_name=execution_input['ModelName']  \n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Create the transform step\n",
    "\n",
    "In the following cell we create the transform step. See  [TransformStep](https://aws-step-functions-data-science-sdk.readthedocs.io/en/latest/sagemaker.html#stepfunctions.steps.sagemaker.TransformStep) in the AWS Step Functions Data Science SDK documentation."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [],
   "source": [
    "transform_step = steps.TransformStep(\n",
    "    'Transform Input Dataset',\n",
    "    transformer=xgb.transformer(\n",
    "        instance_count=1,\n",
    "        instance_type='ml.m5.large'\n",
    "    ),\n",
    "    job_name=execution_input['JobName'],     \n",
    "    model_name=execution_input['ModelName'], \n",
    "    data=test_s3_file,\n",
    "    content_type='text/libsvm'\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Create an endpoint configuration step\n",
    "\n",
    "In the following cell we create an endpoint configuration step. See [EndpointConfigStep](https://aws-step-functions-data-science-sdk.readthedocs.io/en/latest/sagemaker.html#stepfunctions.steps.sagemaker.EndpointConfigStep) in the AWS Step Functions Data Science SDK documentation.\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [],
   "source": [
    "endpoint_config_step = steps.EndpointConfigStep(\n",
    "    \"Create Endpoint Config\",\n",
    "    endpoint_config_name=execution_input['ModelName'],\n",
    "    model_name=execution_input['ModelName'],\n",
    "    initial_instance_count=1,\n",
    "    instance_type='ml.m5.large'\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Create an endpoint\n",
    "\n",
    "In the following cell we create a step to deploy the trained model to an endpoint in AWS SageMaker. See [EndpointStep](https://aws-step-functions-data-science-sdk.readthedocs.io/en/latest/sagemaker.html#stepfunctions.steps.sagemaker.EndpointStep) in the AWS Step Functions Data Science SDK documentation."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [],
   "source": [
    "endpoint_step = steps.EndpointStep(\n",
    "    \"Create Endpoint\",\n",
    "    endpoint_name=execution_input['EndpointName'],\n",
    "    endpoint_config_name=execution_input['ModelName']\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Chain together steps for your workflow\n",
    "\n",
    "Create your workflow definition by chaining the steps together. See [Chain](https://aws-step-functions-data-science-sdk.readthedocs.io/en/latest/sagemaker.html#stepfunctions.steps.states.Chain) in the AWS Step Functions Data Science SDK documentation."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [],
   "source": [
    "workflow_definition = steps.Chain([\n",
    "    training_step,\n",
    "    model_step,\n",
    "    transform_step,\n",
    "    endpoint_config_step,\n",
    "    endpoint_step\n",
    "])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Create your workflow using the workflow definition above, and render the graph with [render_graph](https://aws-step-functions-data-science-sdk.readthedocs.io/en/latest/workflow.html#stepfunctions.workflow.Workflow.render_graph)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 48,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Workflow(name='MyTrainTransformDeploy_v1', role='arn:aws:iam::806570384721:role/StepFunctionsExecutionRole', state_machine_arn=None)\n"
     ]
    }
   ],
   "source": [
    "workflow = Workflow(\n",
    "    name='MyTrainTransformDeploy_v1',\n",
    "    definition=workflow_definition,\n",
    "    role=workflow_execution_role,\n",
    "    execution_input=execution_input\n",
    ")\n",
    "\n",
    "print(workflow)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 49,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "\n",
       "<link rel=\"stylesheet\" type=\"text/css\" href=\"https://do0of8uwbahzz.cloudfront.net/graph.css\">\n",
       "<div id=\"graph-579\" class=\"workflowgraph\">\n",
       "    \n",
       "    <svg></svg>\n",
       "    \n",
       "</div>\n",
       "\n",
       "<script type=\"text/javascript\">\n",
       "\n",
       "require.config({\n",
       "    paths: {\n",
       "        sfn: \"https://do0of8uwbahzz.cloudfront.net/sfn\",\n",
       "    }\n",
       "});\n",
       "\n",
       "require(['sfn'], function(sfn) {\n",
       "    var options = {\n",
       "        width: $('#graph-579').width(),\n",
       "        height: 600,\n",
       "        layout: 'LR',\n",
       "        resizeHeight: true\n",
       "    };\n",
       "\n",
       "    var definition = {\"StartAt\": \"Train Step\", \"States\": {\"Train Step\": {\"Resource\": \"arn:aws:states:::sagemaker:createTrainingJob.sync\", \"Parameters\": {\"AlgorithmSpecification\": {\"TrainingImage\": \"811284229777.dkr.ecr.us-east-1.amazonaws.com/xgboost:1\", \"TrainingInputMode\": \"File\"}, \"OutputDataConfig\": {\"S3OutputPath\": \"https://s3-us-east-1.amazonaws.com/sagemaker-us-east-1-806570384721/sagemaker/DEMO-xgboost-regression/single-xgboost\"}, \"StoppingCondition\": {\"MaxRuntimeInSeconds\": 86400}, \"ResourceConfig\": {\"InstanceCount\": 1, \"InstanceType\": \"ml.m4.4xlarge\", \"VolumeSizeInGB\": 5}, \"RoleArn\": \"arn:aws:iam::806570384721:role/service-role/AmazonSageMaker-ExecutionRole-20191201T115647\", \"InputDataConfig\": [{\"DataSource\": {\"S3DataSource\": {\"S3DataType\": \"S3Prefix\", \"S3Uri\": \"https://s3-us-east-1.amazonaws.com/sagemaker-us-east-1-806570384721/sagemaker/DEMO-xgboost-regression/train\", \"S3DataDistributionType\": \"FullyReplicated\"}}, \"ContentType\": \"libsvm\", \"ChannelName\": \"train\"}, {\"DataSource\": {\"S3DataSource\": {\"S3DataType\": \"S3Prefix\", \"S3Uri\": \"https://s3-us-east-1.amazonaws.com/sagemaker-us-east-1-806570384721/sagemaker/DEMO-xgboost-regression/validation\", \"S3DataDistributionType\": \"FullyReplicated\"}}, \"ContentType\": \"libsvm\", \"ChannelName\": \"validation\"}], \"HyperParameters\": {\"objective\": \"reg:linear\", \"num_round\": \"50\", \"max_depth\": \"5\", \"eta\": \"0.2\", \"gamme\": \"4\", \"min_child_weight\": \"6\", \"subsample\": \"0.7\", \"silent\": \"0\"}, \"TrainingJobName.$\": \"$$.Execution.Input['JobName']\"}, \"Type\": \"Task\", \"Next\": \"Save model\"}, \"Save model\": {\"Parameters\": {\"ExecutionRoleArn\": \"arn:aws:iam::806570384721:role/service-role/AmazonSageMaker-ExecutionRole-20191201T115647\", \"ModelName.$\": \"$$.Execution.Input['ModelName']\", \"PrimaryContainer\": {\"Environment\": {}, \"Image\": \"811284229777.dkr.ecr.us-east-1.amazonaws.com/xgboost:1\", \"ModelDataUrl.$\": \"$['ModelArtifacts']['S3ModelArtifacts']\"}}, \"Resource\": \"arn:aws:states:::sagemaker:createModel\", \"Type\": \"Task\", \"Next\": \"Transform Input Dataset\"}, \"Transform Input Dataset\": {\"Resource\": \"arn:aws:states:::sagemaker:createTransformJob.sync\", \"Parameters\": {\"TransformJobName.$\": \"$$.Execution.Input['JobName']\", \"ModelName.$\": \"$$.Execution.Input['ModelName']\", \"TransformInput\": {\"DataSource\": {\"S3DataSource\": {\"S3DataType\": \"S3Prefix\", \"S3Uri\": \"https://s3-us-east-1.amazonaws.com/sagemaker-us-east-1-806570384721/sagemaker/DEMO-xgboost-regression/test\"}}, \"ContentType\": \"text/libsvm\"}, \"TransformOutput\": {\"S3OutputPath\": \"s3://sagemaker-us-east-1-806570384721/xgboost-2020-01-14-14-11-43-440\"}, \"TransformResources\": {\"InstanceCount\": 1, \"InstanceType\": \"ml.m5.large\"}}, \"Type\": \"Task\", \"Next\": \"Create Endpoint Config\"}, \"Create Endpoint Config\": {\"Resource\": \"arn:aws:states:::sagemaker:createEndpointConfig\", \"Parameters\": {\"EndpointConfigName.$\": \"$$.Execution.Input['ModelName']\", \"ProductionVariants\": [{\"InitialInstanceCount\": 1, \"InstanceType\": \"ml.m5.large\", \"ModelName.$\": \"$$.Execution.Input['ModelName']\", \"VariantName\": \"AllTraffic\"}]}, \"Type\": \"Task\", \"Next\": \"Create Endpoint\"}, \"Create Endpoint\": {\"Resource\": \"arn:aws:states:::sagemaker:createEndpoint\", \"Parameters\": {\"EndpointConfigName.$\": \"$$.Execution.Input['ModelName']\", \"EndpointName.$\": \"$$.Execution.Input['EndpointName']\"}, \"Type\": \"Task\", \"End\": true}}};\n",
       "    var elementId = '#graph-579';\n",
       "\n",
       "    var graph = new sfn.StateMachineGraph(definition, elementId, options);\n",
       "    graph.render();\n",
       "});\n",
       "\n",
       "</script>\n"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "execution_count": 49,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "workflow.render_graph()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Create the workflow in AWS Step Functions with [create](https://aws-step-functions-data-science-sdk.readthedocs.io/en/latest/workflow.html#stepfunctions.workflow.Workflow.create)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 54,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\u001b[33m[WARNING] The workflow already exists on AWS Step Functions. No action will be performed.\u001b[0m\n"
     ]
    }
   ],
   "source": [
    "state_machine_arn = workflow.create()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 55,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "arn:aws:states:us-east-1:806570384721:stateMachine:MyTrainTransformDeploy_v1\n"
     ]
    }
   ],
   "source": [
    "print(state_machine_arn)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 58,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Workflow(name='MyTrainTransformDeploy_v1', role='arn:aws:iam::806570384721:role/StepFunctionsExecutionRole', state_machine_arn='arn:aws:states:us-east-1:806570384721:stateMachine:MyTrainTransformDeploy_v1')\n"
     ]
    }
   ],
   "source": [
    "my_attached_workflow = workflow.attach(state_machine_arn=state_machine_arn)\n",
    "print(my_attached_workflow)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Run the workflow with [execute](https://aws-step-functions-data-science-sdk.readthedocs.io/en/latest/workflow.html#stepfunctions.workflow.Workflow.execute)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\u001b[32m[INFO] Workflow execution started successfully on AWS Step Functions.\u001b[0m\n"
     ]
    }
   ],
   "source": [
    "job_name = 'regression-{}'.format(uuid.uuid1().hex)\n",
    "print(job_name)\n",
    "model_name = 'regression-{}'.format(uuid.uuid1().hex)\n",
    "print(model_name)\n",
    "endpoint_name = 'regression-{}'.format(uuid.uuid1().hex)\n",
    "print(endpoint_name)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 68,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\u001b[32m[INFO] Workflow execution started successfully on AWS Step Functions.\u001b[0m\n",
      "Execution(execution_arn='arn:aws:states:us-east-1:806570384721:execution:MyTrainTransformDeploy_v1:6ef758fe-eabe-40b1-8bfc-8e9430ed5313', name=None, status=<ExecutionStatus.Running: 'RUNNING'>, start_date=datetime.datetime(2020, 1, 14, 15, 29, 24, 716000, tzinfo=tzlocal()))\n"
     ]
    }
   ],
   "source": [
    "execution = my_attached_workflow.execute(\n",
    "    inputs={\n",
    "        'JobName': job_name, # Each Sagemaker Job requires a unique name\n",
    "        'ModelName': model_name, # Each Model requires a unique name,\n",
    "        'EndpointName': endpoint_name # Each Endpoint requires a unique name,\n",
    "    }\n",
    ")\n",
    "print(execution)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 64,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "arn:aws:states:us-east-1:806570384721:execution:MyTrainTransformDeploy_v1:f4827dc0-4361-48f8-8dd3-4c45c85c452e\n"
     ]
    }
   ],
   "source": [
    "execution_arn=execution.execution_arn\n",
    "print(execution_arn)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 66,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "ExecutionStatus.Running\n"
     ]
    }
   ],
   "source": [
    "execution_state=execution.status\n",
    "print(execution_state)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 67,
   "metadata": {
    "scrolled": false
   },
   "outputs": [
    {
     "data": {
      "text/html": [
       "\n",
       "<link rel=\"stylesheet\" type=\"text/css\" href=\"https://do0of8uwbahzz.cloudfront.net/graph.css\">\n",
       "<div id=\"graph-998\" class=\"workflowgraph\">\n",
       "    \n",
       "    <style>\n",
       "        .graph-legend ul {\n",
       "            list-style-type: none;\n",
       "            padding: 10px;\n",
       "            padding-left: 0;\n",
       "            margin: 0;\n",
       "            position: absolute;\n",
       "            top: 0;\n",
       "            background: transparent;\n",
       "        }\n",
       "\n",
       "        .graph-legend li {\n",
       "            margin-left: 10px;\n",
       "            display: inline-block;\n",
       "        }\n",
       "\n",
       "        .graph-legend li > div {\n",
       "            width: 10px;\n",
       "            height: 10px;\n",
       "            display: inline-block;\n",
       "        }\n",
       "\n",
       "        .graph-legend .success { background-color: #2BD62E }\n",
       "        .graph-legend .failed { background-color: #DE322F }\n",
       "        .graph-legend .cancelled { background-color: #DDDDDD }\n",
       "        .graph-legend .in-progress { background-color: #53C9ED }\n",
       "        .graph-legend .caught-error { background-color: #FFA500 }\n",
       "    </style>\n",
       "    <div class=\"graph-legend\">\n",
       "        <ul>\n",
       "            <li>\n",
       "                <div class=\"success\"></div>\n",
       "                <span>Success</span>\n",
       "            </li>\n",
       "            <li>\n",
       "                <div class=\"failed\"></div>\n",
       "                <span>Failed</span>\n",
       "            </li>\n",
       "            <li>\n",
       "                <div class=\"cancelled\"></div>\n",
       "                <span>Cancelled</span>\n",
       "            </li>\n",
       "            <li>\n",
       "                <div class=\"in-progress\"></div>\n",
       "                <span>In Progress</span>\n",
       "            </li>\n",
       "            <li>\n",
       "                <div class=\"caught-error\"></div>\n",
       "                <span>Caught Error</span>\n",
       "            </li>\n",
       "        </ul>\n",
       "    </div>\n",
       "\n",
       "    <svg></svg>\n",
       "    <a href=\"https://console.aws.amazon.com/states/home?region=us-east-1#/executions/details/arn:aws:states:us-east-1:806570384721:execution:MyTrainTransformDeploy_v1:f4827dc0-4361-48f8-8dd3-4c45c85c452e\" target=\"_blank\"> Inspect in AWS Step Functions </a>\n",
       "</div>\n",
       "\n",
       "<script type=\"text/javascript\">\n",
       "\n",
       "require.config({\n",
       "    paths: {\n",
       "        sfn: \"https://do0of8uwbahzz.cloudfront.net/sfn\",\n",
       "    }\n",
       "});\n",
       "\n",
       "require(['sfn'], function(sfn) {\n",
       "    var options = {\n",
       "        width: $('#graph-998').width(),\n",
       "        height: 1000,\n",
       "        layout: 'LR',\n",
       "        resizeHeight: true\n",
       "    };\n",
       "\n",
       "    var definition = {\"StartAt\": \"Train Step\", \"States\": {\"Train Step\": {\"Resource\": \"arn:aws:states:::sagemaker:createTrainingJob.sync\", \"Parameters\": {\"AlgorithmSpecification\": {\"TrainingImage\": \"811284229777.dkr.ecr.us-east-1.amazonaws.com/xgboost:1\", \"TrainingInputMode\": \"File\"}, \"OutputDataConfig\": {\"S3OutputPath\": \"https://s3-us-east-1.amazonaws.com/sagemaker-us-east-1-806570384721/sagemaker/DEMO-xgboost-regression/single-xgboost\"}, \"StoppingCondition\": {\"MaxRuntimeInSeconds\": 86400}, \"ResourceConfig\": {\"InstanceCount\": 1, \"InstanceType\": \"ml.m4.4xlarge\", \"VolumeSizeInGB\": 5}, \"RoleArn\": \"arn:aws:iam::806570384721:role/service-role/AmazonSageMaker-ExecutionRole-20191201T115647\", \"InputDataConfig\": [{\"DataSource\": {\"S3DataSource\": {\"S3DataType\": \"S3Prefix\", \"S3Uri\": \"https://s3-us-east-1.amazonaws.com/sagemaker-us-east-1-806570384721/sagemaker/DEMO-xgboost-regression/train\", \"S3DataDistributionType\": \"FullyReplicated\"}}, \"ContentType\": \"libsvm\", \"ChannelName\": \"train\"}, {\"DataSource\": {\"S3DataSource\": {\"S3DataType\": \"S3Prefix\", \"S3Uri\": \"https://s3-us-east-1.amazonaws.com/sagemaker-us-east-1-806570384721/sagemaker/DEMO-xgboost-regression/validation\", \"S3DataDistributionType\": \"FullyReplicated\"}}, \"ContentType\": \"libsvm\", \"ChannelName\": \"validation\"}], \"HyperParameters\": {\"objective\": \"reg:linear\", \"num_round\": \"50\", \"max_depth\": \"5\", \"eta\": \"0.2\", \"gamme\": \"4\", \"min_child_weight\": \"6\", \"subsample\": \"0.7\", \"silent\": \"0\"}, \"TrainingJobName.$\": \"$$.Execution.Input['JobName']\"}, \"Type\": \"Task\", \"Next\": \"Save model\"}, \"Save model\": {\"Parameters\": {\"ExecutionRoleArn\": \"arn:aws:iam::806570384721:role/service-role/AmazonSageMaker-ExecutionRole-20191201T115647\", \"ModelName.$\": \"$$.Execution.Input['ModelName']\", \"PrimaryContainer\": {\"Environment\": {}, \"Image\": \"811284229777.dkr.ecr.us-east-1.amazonaws.com/xgboost:1\", \"ModelDataUrl.$\": \"$['ModelArtifacts']['S3ModelArtifacts']\"}}, \"Resource\": \"arn:aws:states:::sagemaker:createModel\", \"Type\": \"Task\", \"Next\": \"Transform Input Dataset\"}, \"Transform Input Dataset\": {\"Resource\": \"arn:aws:states:::sagemaker:createTransformJob.sync\", \"Parameters\": {\"TransformJobName.$\": \"$$.Execution.Input['JobName']\", \"ModelName.$\": \"$$.Execution.Input['ModelName']\", \"TransformInput\": {\"DataSource\": {\"S3DataSource\": {\"S3DataType\": \"S3Prefix\", \"S3Uri\": \"https://s3-us-east-1.amazonaws.com/sagemaker-us-east-1-806570384721/sagemaker/DEMO-xgboost-regression/test\"}}, \"ContentType\": \"text/libsvm\"}, \"TransformOutput\": {\"S3OutputPath\": \"s3://sagemaker-us-east-1-806570384721/xgboost-2020-01-14-14-11-43-440\"}, \"TransformResources\": {\"InstanceCount\": 1, \"InstanceType\": \"ml.m5.large\"}}, \"Type\": \"Task\", \"Next\": \"Create Endpoint Config\"}, \"Create Endpoint Config\": {\"Resource\": \"arn:aws:states:::sagemaker:createEndpointConfig\", \"Parameters\": {\"EndpointConfigName.$\": \"$$.Execution.Input['ModelName']\", \"ProductionVariants\": [{\"InitialInstanceCount\": 1, \"InstanceType\": \"ml.m5.large\", \"ModelName.$\": \"$$.Execution.Input['ModelName']\", \"VariantName\": \"AllTraffic\"}]}, \"Type\": \"Task\", \"Next\": \"Create Endpoint\"}, \"Create Endpoint\": {\"Resource\": \"arn:aws:states:::sagemaker:createEndpoint\", \"Parameters\": {\"EndpointConfigName.$\": \"$$.Execution.Input['ModelName']\", \"EndpointName.$\": \"$$.Execution.Input['EndpointName']\"}, \"Type\": \"Task\", \"End\": true}}};\n",
       "    var elementId = '#graph-998';\n",
       "    var events = { 'events': [{\"timestamp\": 1579015481.316, \"type\": \"ExecutionStarted\", \"id\": 1, \"previousEventId\": 0, \"executionStartedEventDetails\": {\"input\": \"{\\n    \\\"JobName\\\": \\\"regression-8fa8148436da11ea97286d708cc45e75\\\",\\n    \\\"ModelName\\\": \\\"regression-8fa817e036da11ea97286d708cc45e75\\\",\\n    \\\"EndpointName\\\": \\\"regression-8fa819d436da11ea97286d708cc45e75\\\"\\n}\", \"roleArn\": \"arn:aws:iam::806570384721:role/StepFunctionsExecutionRole\"}}, {\"timestamp\": 1579015481.341, \"type\": \"TaskStateEntered\", \"id\": 2, \"previousEventId\": 0, \"stateEnteredEventDetails\": {\"name\": \"Train Step\", \"input\": \"{\\n    \\\"JobName\\\": \\\"regression-8fa8148436da11ea97286d708cc45e75\\\",\\n    \\\"ModelName\\\": \\\"regression-8fa817e036da11ea97286d708cc45e75\\\",\\n    \\\"EndpointName\\\": \\\"regression-8fa819d436da11ea97286d708cc45e75\\\"\\n}\"}}, {\"timestamp\": 1579015481.341, \"type\": \"TaskScheduled\", \"id\": 3, \"previousEventId\": 2, \"taskScheduledEventDetails\": {\"resourceType\": \"sagemaker\", \"resource\": \"createTrainingJob.sync\", \"region\": \"us-east-1\", \"parameters\": \"{\\\"AlgorithmSpecification\\\":{\\\"TrainingImage\\\":\\\"811284229777.dkr.ecr.us-east-1.amazonaws.com/xgboost:1\\\",\\\"TrainingInputMode\\\":\\\"File\\\"},\\\"OutputDataConfig\\\":{\\\"S3OutputPath\\\":\\\"https://s3-us-east-1.amazonaws.com/sagemaker-us-east-1-806570384721/sagemaker/DEMO-xgboost-regression/single-xgboost\\\"},\\\"StoppingCondition\\\":{\\\"MaxRuntimeInSeconds\\\":86400},\\\"ResourceConfig\\\":{\\\"InstanceCount\\\":1,\\\"InstanceType\\\":\\\"ml.m4.4xlarge\\\",\\\"VolumeSizeInGB\\\":5},\\\"RoleArn\\\":\\\"arn:aws:iam::806570384721:role/service-role/AmazonSageMaker-ExecutionRole-20191201T115647\\\",\\\"InputDataConfig\\\":[{\\\"DataSource\\\":{\\\"S3DataSource\\\":{\\\"S3DataType\\\":\\\"S3Prefix\\\",\\\"S3Uri\\\":\\\"https://s3-us-east-1.amazonaws.com/sagemaker-us-east-1-806570384721/sagemaker/DEMO-xgboost-regression/train\\\",\\\"S3DataDistributionType\\\":\\\"FullyReplicated\\\"}},\\\"ContentType\\\":\\\"libsvm\\\",\\\"ChannelName\\\":\\\"train\\\"},{\\\"DataSource\\\":{\\\"S3DataSource\\\":{\\\"S3DataType\\\":\\\"S3Prefix\\\",\\\"S3Uri\\\":\\\"https://s3-us-east-1.amazonaws.com/sagemaker-us-east-1-806570384721/sagemaker/DEMO-xgboost-regression/validation\\\",\\\"S3DataDistributionType\\\":\\\"FullyReplicated\\\"}},\\\"ContentType\\\":\\\"libsvm\\\",\\\"ChannelName\\\":\\\"validation\\\"}],\\\"HyperParameters\\\":{\\\"objective\\\":\\\"reg:linear\\\",\\\"num_round\\\":\\\"50\\\",\\\"max_depth\\\":\\\"5\\\",\\\"eta\\\":\\\"0.2\\\",\\\"gamme\\\":\\\"4\\\",\\\"min_child_weight\\\":\\\"6\\\",\\\"subsample\\\":\\\"0.7\\\",\\\"silent\\\":\\\"0\\\"},\\\"TrainingJobName\\\":\\\"regression-8fa8148436da11ea97286d708cc45e75\\\",\\\"Tags\\\":[{\\\"Key\\\":\\\"MANAGED_BY_AWS\\\",\\\"Value\\\":\\\"STARTED_BY_STEP_FUNCTIONS\\\"}]}\"}}, {\"timestamp\": 1579015481.378, \"type\": \"TaskStarted\", \"id\": 4, \"previousEventId\": 3, \"taskStartedEventDetails\": {\"resourceType\": \"sagemaker\", \"resource\": \"createTrainingJob.sync\"}}, {\"timestamp\": 1579015481.608, \"type\": \"TaskSubmitFailed\", \"id\": 5, \"previousEventId\": 4, \"taskSubmitFailedEventDetails\": {\"resourceType\": \"sagemaker\", \"resource\": \"createTrainingJob.sync\", \"error\": \"SageMaker.ResourceInUseException\", \"cause\": \"Training job names must be unique within an AWS account and region, and a training job with this name already exists (arn:aws:sagemaker:us-east-1:806570384721:training-job/regression-8fa8148436da11ea97286d708cc45e75) (Service: AmazonSageMaker; Status Code: 400; Error Code: ResourceInUse; Request ID: 44b029b0-800d-4f0f-bcb6-05c3dc65b650)\"}}, {\"timestamp\": 1579015481.608, \"type\": \"ExecutionFailed\", \"id\": 6, \"previousEventId\": 5, \"executionFailedEventDetails\": {\"error\": \"SageMaker.ResourceInUseException\", \"cause\": \"Training job names must be unique within an AWS account and region, and a training job with this name already exists (arn:aws:sagemaker:us-east-1:806570384721:training-job/regression-8fa8148436da11ea97286d708cc45e75) (Service: AmazonSageMaker; Status Code: 400; Error Code: ResourceInUse; Request ID: 44b029b0-800d-4f0f-bcb6-05c3dc65b650)\"}}] };\n",
       "\n",
       "    var graph = new sfn.StateMachineExecutionGraph(definition, events, elementId, options);\n",
       "    graph.render();\n",
       "});\n",
       "\n",
       "</script>\n"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "execution_count": 67,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "execution.render_progress()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Render workflow progress with the [render_progress](https://aws-step-functions-data-science-sdk.readthedocs.io/en/latest/workflow.html#stepfunctions.workflow.Execution.render_progress).\n",
    "\n",
    "This generates a snapshot of the current state of your workflow as it executes. This is a static image. Run the cell again to check progress. "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Use [list_events](https://aws-step-functions-data-science-sdk.readthedocs.io/en/latest/workflow.html#stepfunctions.workflow.Execution.list_events) to list all events in the workflow execution."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {
    "scrolled": false
   },
   "outputs": [
    {
     "data": {
      "text/html": [
       "\n",
       "    <style>\n",
       "        \n",
       "    .table-widget {\n",
       "        width: 100%;\n",
       "        font-size: 14px;\n",
       "        line-height: 28px;\n",
       "        color: #545b64;\n",
       "        border-spacing: 0;\n",
       "        background-color: #fff;\n",
       "        border-color: grey;\n",
       "        background: #fafafa;\n",
       "    }\n",
       "\n",
       "    .table-widget thead th {\n",
       "        text-align: left !important;\n",
       "        color: #879596;\n",
       "        padding: 0.3em 2em;\n",
       "        border-bottom: 1px solid #eaeded;\n",
       "        min-height: 4rem;\n",
       "        line-height: 28px;\n",
       "    }\n",
       "\n",
       "    .table-widget thead th:first-of-type {\n",
       "    }\n",
       "\n",
       "    .table-widget td {\n",
       "        overflow-wrap: break-word;\n",
       "        padding: 0.4em 2em;\n",
       "        line-height: 28px;\n",
       "        text-align: left !important;\n",
       "        background: #fff;\n",
       "        border-bottom: 1px solid #eaeded;\n",
       "        border-top: 1px solid transparent;\n",
       "    }\n",
       "\n",
       "    .table-widget td:before {\n",
       "        content: \"\";\n",
       "        height: 3rem;\n",
       "    }\n",
       "\n",
       "    a {\n",
       "        cursor: pointer;\n",
       "        text-decoration: none !important;\n",
       "        color: #007dbc;\n",
       "    }\n",
       "\n",
       "    a:hover {\n",
       "        text-decoration: underline !important;\n",
       "    }\n",
       "\n",
       "    a.disabled {\n",
       "        color: black;\n",
       "        cursor: default;\n",
       "        pointer-events: none;\n",
       "    }\n",
       "\n",
       "    .hide {\n",
       "        display: none;\n",
       "    }\n",
       "\n",
       "    pre {\n",
       "        white-space: pre-wrap;\n",
       "    }\n",
       "\n",
       "        \n",
       "    .table-widget .clickable-cell {\n",
       "        padding-left: 0.1em;\n",
       "        cursor: pointer;\n",
       "    }\n",
       "\n",
       "    .toggle-icon {\n",
       "        display: inline-block;\n",
       "        width: 0;\n",
       "        height: 0;\n",
       "        border-top: 5px solid transparent;\n",
       "        border-left: 8px solid #545b64;\n",
       "        border-bottom: 5px solid transparent;\n",
       "        margin-right: 5px;\n",
       "    }\n",
       "\n",
       "    .toggle-icon.open {\n",
       "        -webkit-transform: rotate(90deg);\n",
       "        -ms-transform: rotate(90deg);\n",
       "        transform: rotate(90deg);\n",
       "    }\n",
       "\n",
       "    </style>\n",
       "    <table class=\"table-widget\">\n",
       "        <thead>\n",
       "            <tr>\n",
       "                <th style=\"width: 60px\">ID</th>\n",
       "                <th>Type</th>\n",
       "                <th>Step</th>\n",
       "                <th>Resource</th>\n",
       "                <th>Elapsed Time (ms)</th>\n",
       "                <th>Timestamp</th>\n",
       "            </tr>\n",
       "        </thead>\n",
       "        <tbody>\n",
       "            \n",
       "    <tr class=\"awsui-table-row\">\n",
       "        <td class=\"awsui-util-pl-xs clickable-cell\">\n",
       "            <div class=\"toggle-icon\"></div>\n",
       "            <span>1</span>\n",
       "        </td>\n",
       "        <td>ExecutionStarted</td>\n",
       "        <td></td>\n",
       "        <td><a class='disabled' target=\"_blank\">-</a></td>\n",
       "        <td>0.0</td>\n",
       "        <td>Jan 14, 2020 02:12:53.994 PM</td>\n",
       "    </tr>\n",
       "    <tr class=\"hide\">\n",
       "        <td class=\"execution-event-detail\" colspan=\"6\">\n",
       "            <pre>{\n",
       "    \"input\": {\n",
       "        \"JobName\": \"regression-f4b22a4836d711ea97286d708cc45e75\",\n",
       "        \"ModelName\": \"regression-f4b2354c36d711ea97286d708cc45e75\",\n",
       "        \"EndpointName\": \"regression-f4b2361e36d711ea97286d708cc45e75\"\n",
       "    },\n",
       "    \"roleArn\": \"arn:aws:iam::806570384721:role/StepFunctionsExecutionRole\"\n",
       "}</pre>\n",
       "        </td>\n",
       "    </tr>\n",
       "\n",
       "\n",
       "    <tr class=\"awsui-table-row\">\n",
       "        <td class=\"awsui-util-pl-xs clickable-cell\">\n",
       "            <div class=\"toggle-icon\"></div>\n",
       "            <span>2</span>\n",
       "        </td>\n",
       "        <td>TaskStateEntered</td>\n",
       "        <td>Train Step</td>\n",
       "        <td><a class='disabled' target=\"_blank\">-</a></td>\n",
       "        <td>29.0</td>\n",
       "        <td>Jan 14, 2020 02:12:54.023 PM</td>\n",
       "    </tr>\n",
       "    <tr class=\"hide\">\n",
       "        <td class=\"execution-event-detail\" colspan=\"6\">\n",
       "            <pre>{\n",
       "    \"name\": \"Train Step\",\n",
       "    \"input\": {\n",
       "        \"JobName\": \"regression-f4b22a4836d711ea97286d708cc45e75\",\n",
       "        \"ModelName\": \"regression-f4b2354c36d711ea97286d708cc45e75\",\n",
       "        \"EndpointName\": \"regression-f4b2361e36d711ea97286d708cc45e75\"\n",
       "    }\n",
       "}</pre>\n",
       "        </td>\n",
       "    </tr>\n",
       "\n",
       "\n",
       "    <tr class=\"awsui-table-row\">\n",
       "        <td class=\"awsui-util-pl-xs clickable-cell\">\n",
       "            <div class=\"toggle-icon\"></div>\n",
       "            <span>3</span>\n",
       "        </td>\n",
       "        <td>TaskScheduled</td>\n",
       "        <td>Train Step</td>\n",
       "        <td><a href=\"https://console.aws.amazon.com/sagemaker/home?region=us-east-1#/jobs/regression-f4b22a4836d711ea97286d708cc45e75\" target=\"_blank\">Sagemaker training job</a></td>\n",
       "        <td>29.0</td>\n",
       "        <td>Jan 14, 2020 02:12:54.023 PM</td>\n",
       "    </tr>\n",
       "    <tr class=\"hide\">\n",
       "        <td class=\"execution-event-detail\" colspan=\"6\">\n",
       "            <pre>{\n",
       "    \"resourceType\": \"sagemaker\",\n",
       "    \"resource\": \"createTrainingJob.sync\",\n",
       "    \"region\": \"us-east-1\",\n",
       "    \"parameters\": {\n",
       "        \"AlgorithmSpecification\": {\n",
       "            \"TrainingImage\": \"811284229777.dkr.ecr.us-east-1.amazonaws.com/xgboost:1\",\n",
       "            \"TrainingInputMode\": \"File\"\n",
       "        },\n",
       "        \"OutputDataConfig\": {\n",
       "            \"S3OutputPath\": \"https://s3-us-east-1.amazonaws.com/sagemaker-us-east-1-806570384721/sagemaker/DEMO-xgboost-regression/single-xgboost\"\n",
       "        },\n",
       "        \"StoppingCondition\": {\n",
       "            \"MaxRuntimeInSeconds\": 86400\n",
       "        },\n",
       "        \"ResourceConfig\": {\n",
       "            \"InstanceCount\": 1,\n",
       "            \"InstanceType\": \"ml.m4.4xlarge\",\n",
       "            \"VolumeSizeInGB\": 5\n",
       "        },\n",
       "        \"RoleArn\": \"arn:aws:iam::806570384721:role/service-role/AmazonSageMaker-ExecutionRole-20191201T115647\",\n",
       "        \"InputDataConfig\": [\n",
       "            {\n",
       "                \"DataSource\": {\n",
       "                    \"S3DataSource\": {\n",
       "                        \"S3DataType\": \"S3Prefix\",\n",
       "                        \"S3Uri\": \"https://s3-us-east-1.amazonaws.com/sagemaker-us-east-1-806570384721/sagemaker/DEMO-xgboost-regression/train\",\n",
       "                        \"S3DataDistributionType\": \"FullyReplicated\"\n",
       "                    }\n",
       "                },\n",
       "                \"ContentType\": \"libsvm\",\n",
       "                \"ChannelName\": \"train\"\n",
       "            },\n",
       "            {\n",
       "                \"DataSource\": {\n",
       "                    \"S3DataSource\": {\n",
       "                        \"S3DataType\": \"S3Prefix\",\n",
       "                        \"S3Uri\": \"https://s3-us-east-1.amazonaws.com/sagemaker-us-east-1-806570384721/sagemaker/DEMO-xgboost-regression/validation\",\n",
       "                        \"S3DataDistributionType\": \"FullyReplicated\"\n",
       "                    }\n",
       "                },\n",
       "                \"ContentType\": \"libsvm\",\n",
       "                \"ChannelName\": \"validation\"\n",
       "            }\n",
       "        ],\n",
       "        \"HyperParameters\": {\n",
       "            \"objective\": \"reg:linear\",\n",
       "            \"num_round\": \"50\",\n",
       "            \"max_depth\": \"5\",\n",
       "            \"eta\": \"0.2\",\n",
       "            \"gamme\": \"4\",\n",
       "            \"min_child_weight\": \"6\",\n",
       "            \"subsample\": \"0.7\",\n",
       "            \"silent\": \"0\"\n",
       "        },\n",
       "        \"TrainingJobName\": \"regression-f4b22a4836d711ea97286d708cc45e75\",\n",
       "        \"Tags\": [\n",
       "            {\n",
       "                \"Key\": \"MANAGED_BY_AWS\",\n",
       "                \"Value\": \"STARTED_BY_STEP_FUNCTIONS\"\n",
       "            }\n",
       "        ]\n",
       "    }\n",
       "}</pre>\n",
       "        </td>\n",
       "    </tr>\n",
       "\n",
       "\n",
       "    <tr class=\"awsui-table-row\">\n",
       "        <td class=\"awsui-util-pl-xs clickable-cell\">\n",
       "            <div class=\"toggle-icon\"></div>\n",
       "            <span>4</span>\n",
       "        </td>\n",
       "        <td>TaskStarted</td>\n",
       "        <td>Train Step</td>\n",
       "        <td><a href=\"https://console.aws.amazon.com/sagemaker/home?region=us-east-1#/jobs/regression-f4b22a4836d711ea97286d708cc45e75\" target=\"_blank\">Sagemaker training job</a></td>\n",
       "        <td>105.0</td>\n",
       "        <td>Jan 14, 2020 02:12:54.099 PM</td>\n",
       "    </tr>\n",
       "    <tr class=\"hide\">\n",
       "        <td class=\"execution-event-detail\" colspan=\"6\">\n",
       "            <pre>{\n",
       "    \"resourceType\": \"sagemaker\",\n",
       "    \"resource\": \"createTrainingJob.sync\"\n",
       "}</pre>\n",
       "        </td>\n",
       "    </tr>\n",
       "\n",
       "\n",
       "    <tr class=\"awsui-table-row\">\n",
       "        <td class=\"awsui-util-pl-xs clickable-cell\">\n",
       "            <div class=\"toggle-icon\"></div>\n",
       "            <span>5</span>\n",
       "        </td>\n",
       "        <td>TaskSubmitted</td>\n",
       "        <td>Train Step</td>\n",
       "        <td><a href=\"https://console.aws.amazon.com/sagemaker/home?region=us-east-1#/jobs/regression-f4b22a4836d711ea97286d708cc45e75\" target=\"_blank\">Sagemaker training job</a></td>\n",
       "        <td>468.0</td>\n",
       "        <td>Jan 14, 2020 02:12:54.462 PM</td>\n",
       "    </tr>\n",
       "    <tr class=\"hide\">\n",
       "        <td class=\"execution-event-detail\" colspan=\"6\">\n",
       "            <pre>{\n",
       "    \"resourceType\": \"sagemaker\",\n",
       "    \"resource\": \"createTrainingJob.sync\",\n",
       "    \"output\": {\n",
       "        \"SdkHttpMetadata\": {\n",
       "            \"HttpHeaders\": {\n",
       "                \"Content-Length\": \"118\",\n",
       "                \"Content-Type\": \"application/x-amz-json-1.1\",\n",
       "                \"Date\": \"Tue, 14 Jan 2020 14:12:54 GMT\",\n",
       "                \"x-amzn-RequestId\": \"07d9f369-695c-461c-917d-024e354223f9\"\n",
       "            },\n",
       "            \"HttpStatusCode\": 200\n",
       "        },\n",
       "        \"SdkResponseMetadata\": {\n",
       "            \"RequestId\": \"07d9f369-695c-461c-917d-024e354223f9\"\n",
       "        },\n",
       "        \"TrainingJobArn\": \"arn:aws:sagemaker:us-east-1:806570384721:training-job/regression-f4b22a4836d711ea97286d708cc45e75\"\n",
       "    }\n",
       "}</pre>\n",
       "        </td>\n",
       "    </tr>\n",
       "\n",
       "        </tbody>\n",
       "    </table>\n",
       "    <script type=\"text/javascript\">\n",
       "        \n",
       "    var clickableCells = document.getElementsByClassName(\"clickable-cell\");\n",
       "    for (var cell of clickableCells) {\n",
       "        cell.addEventListener(\"click\", function(e) {\n",
       "            var currentRow = e.srcElement.closest(\"tr\");\n",
       "            var toggleRow = currentRow.nextElementSibling;\n",
       "            var toggleArrow = currentRow.getElementsByClassName(\"toggle-icon\")[0];\n",
       "\n",
       "            toggleRow.classList.toggle(\"hide\");\n",
       "            toggleArrow.classList.toggle(\"open\");\n",
       "        });\n",
       "    }\n",
       "\n",
       "    </script>\n"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "execution_count": 20,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "execution.list_events(html=True)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Use [list_executions](https://aws-step-functions-data-science-sdk.readthedocs.io/en/latest/workflow.html#stepfunctions.workflow.Workflow.list_executions) to list all executions for a specific workflow."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 69,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "\n",
       "    <style>\n",
       "        \n",
       "    .table-widget {\n",
       "        width: 100%;\n",
       "        font-size: 14px;\n",
       "        line-height: 28px;\n",
       "        color: #545b64;\n",
       "        border-spacing: 0;\n",
       "        background-color: #fff;\n",
       "        border-color: grey;\n",
       "        background: #fafafa;\n",
       "    }\n",
       "\n",
       "    .table-widget thead th {\n",
       "        text-align: left !important;\n",
       "        color: #879596;\n",
       "        padding: 0.3em 2em;\n",
       "        border-bottom: 1px solid #eaeded;\n",
       "        min-height: 4rem;\n",
       "        line-height: 28px;\n",
       "    }\n",
       "\n",
       "    .table-widget thead th:first-of-type {\n",
       "    }\n",
       "\n",
       "    .table-widget td {\n",
       "        overflow-wrap: break-word;\n",
       "        padding: 0.4em 2em;\n",
       "        line-height: 28px;\n",
       "        text-align: left !important;\n",
       "        background: #fff;\n",
       "        border-bottom: 1px solid #eaeded;\n",
       "        border-top: 1px solid transparent;\n",
       "    }\n",
       "\n",
       "    .table-widget td:before {\n",
       "        content: \"\";\n",
       "        height: 3rem;\n",
       "    }\n",
       "\n",
       "    a {\n",
       "        cursor: pointer;\n",
       "        text-decoration: none !important;\n",
       "        color: #007dbc;\n",
       "    }\n",
       "\n",
       "    a:hover {\n",
       "        text-decoration: underline !important;\n",
       "    }\n",
       "\n",
       "    a.disabled {\n",
       "        color: black;\n",
       "        cursor: default;\n",
       "        pointer-events: none;\n",
       "    }\n",
       "\n",
       "    .hide {\n",
       "        display: none;\n",
       "    }\n",
       "\n",
       "    pre {\n",
       "        white-space: pre-wrap;\n",
       "    }\n",
       "\n",
       "        \n",
       "    * {\n",
       "        box-sizing: border-box;\n",
       "    }\n",
       "\n",
       "    .table-widget {\n",
       "        min-width: 100%;\n",
       "        font-size: 14px;\n",
       "        line-height: 28px;\n",
       "        color: #545b64;\n",
       "        border-spacing: 0;\n",
       "        background-color: #fff;\n",
       "        border-color: grey;\n",
       "        background: #fafafa;\n",
       "    }\n",
       "\n",
       "    .table-widget thead th {\n",
       "        text-align: left !important;\n",
       "        color: #879596;\n",
       "        padding: 0.3em 2em;\n",
       "        border-bottom: 1px solid #eaeded;\n",
       "        min-height: 4rem;\n",
       "        line-height: 28px;\n",
       "    }\n",
       "\n",
       "    .table-widget td {\n",
       "        /* padding: 24px 18px; */\n",
       "        padding: 0.4em 2em;\n",
       "        line-height: 28px;\n",
       "        text-align: left !important;\n",
       "        background: #fff;\n",
       "        border-bottom: 1px solid #eaeded;\n",
       "        border-top: 1px solid transparent;\n",
       "    }\n",
       "\n",
       "    .table-widget td:before {\n",
       "        content: \"\";\n",
       "        height: 3rem;\n",
       "    }\n",
       "\n",
       "    .table-widget .clickable-cell {\n",
       "        cursor: pointer;\n",
       "    }\n",
       "\n",
       "    .hide {\n",
       "        display: none;\n",
       "    }\n",
       "\n",
       "    .triangle-right {\n",
       "        width: 0;\n",
       "        height: 0;\n",
       "        border-top: 5px solid transparent;\n",
       "        border-left: 8px solid #545b64;\n",
       "        border-bottom: 5px solid transparent;\n",
       "        margin-right: 5px;\n",
       "    }\n",
       "\n",
       "    a.awsui {\n",
       "        text-decoration: none !important;\n",
       "        color: #007dbc;\n",
       "    }\n",
       "\n",
       "    a.awsui:hover {\n",
       "        text-decoration: underline !important;\n",
       "    }\n",
       "\n",
       "    </style>\n",
       "    <table class=\"table-widget\">\n",
       "        <thead>\n",
       "            <tr>\n",
       "                <th>Name</th>\n",
       "                <th>Status</th>\n",
       "                <th>Started</th>\n",
       "                <th>End Time</th>\n",
       "            </tr>\n",
       "        </thead>\n",
       "        <tbody>\n",
       "            \n",
       "    <tr class=\"awsui-table-row\">\n",
       "        <td>\n",
       "            <a href=\"https://console.aws.amazon.com/states/home?region=us-east-1#/executions/details/arn:aws:states:us-east-1:806570384721:execution:MyTrainTransformDeploy_v1:6ef758fe-eabe-40b1-8bfc-8e9430ed5313\" target=\"_blank\" class=\"awsui\">6ef758fe-eabe-40b1-8bfc-8e9430ed5313</a>\n",
       "        </td>\n",
       "        <td>FAILED</td>\n",
       "        <td>Jan 14, 2020 03:29:24.716 PM</td>\n",
       "        <td>Jan 14, 2020 03:29:25.008 PM</td>\n",
       "    </tr>\n",
       "\n",
       "\n",
       "    <tr class=\"awsui-table-row\">\n",
       "        <td>\n",
       "            <a href=\"https://console.aws.amazon.com/states/home?region=us-east-1#/executions/details/arn:aws:states:us-east-1:806570384721:execution:MyTrainTransformDeploy_v1:f4827dc0-4361-48f8-8dd3-4c45c85c452e\" target=\"_blank\" class=\"awsui\">f4827dc0-4361-48f8-8dd3-4c45c85c452e</a>\n",
       "        </td>\n",
       "        <td>FAILED</td>\n",
       "        <td>Jan 14, 2020 03:24:41.316 PM</td>\n",
       "        <td>Jan 14, 2020 03:24:41.608 PM</td>\n",
       "    </tr>\n",
       "\n",
       "\n",
       "    <tr class=\"awsui-table-row\">\n",
       "        <td>\n",
       "            <a href=\"https://console.aws.amazon.com/states/home?region=us-east-1#/executions/details/arn:aws:states:us-east-1:806570384721:execution:MyTrainTransformDeploy_v1:f89b223b-de38-4a6b-a367-2dd3994897ad\" target=\"_blank\" class=\"awsui\">f89b223b-de38-4a6b-a367-2dd3994897ad</a>\n",
       "        </td>\n",
       "        <td>FAILED</td>\n",
       "        <td>Jan 14, 2020 03:24:30.674 PM</td>\n",
       "        <td>Jan 14, 2020 03:24:31.012 PM</td>\n",
       "    </tr>\n",
       "\n",
       "\n",
       "    <tr class=\"awsui-table-row\">\n",
       "        <td>\n",
       "            <a href=\"https://console.aws.amazon.com/states/home?region=us-east-1#/executions/details/arn:aws:states:us-east-1:806570384721:execution:MyTrainTransformDeploy_v1:4fce6bdf-23e5-433b-bda1-c58199f646fa\" target=\"_blank\" class=\"awsui\">4fce6bdf-23e5-433b-bda1-c58199f646fa</a>\n",
       "        </td>\n",
       "        <td>FAILED</td>\n",
       "        <td>Jan 14, 2020 03:23:59.414 PM</td>\n",
       "        <td>Jan 14, 2020 03:23:59.750 PM</td>\n",
       "    </tr>\n",
       "\n",
       "\n",
       "    <tr class=\"awsui-table-row\">\n",
       "        <td>\n",
       "            <a href=\"https://console.aws.amazon.com/states/home?region=us-east-1#/executions/details/arn:aws:states:us-east-1:806570384721:execution:MyTrainTransformDeploy_v1:d452567b-9b9a-4edc-9aac-470aba025b3b\" target=\"_blank\" class=\"awsui\">d452567b-9b9a-4edc-9aac-470aba025b3b</a>\n",
       "        </td>\n",
       "        <td>SUCCEEDED</td>\n",
       "        <td>Jan 14, 2020 02:31:32.988 PM</td>\n",
       "        <td>Jan 14, 2020 02:37:39.372 PM</td>\n",
       "    </tr>\n",
       "\n",
       "\n",
       "    <tr class=\"awsui-table-row\">\n",
       "        <td>\n",
       "            <a href=\"https://console.aws.amazon.com/states/home?region=us-east-1#/executions/details/arn:aws:states:us-east-1:806570384721:execution:MyTrainTransformDeploy_v1:5c4f82b4-0e85-404d-8690-cf0d1675b365\" target=\"_blank\" class=\"awsui\">5c4f82b4-0e85-404d-8690-cf0d1675b365</a>\n",
       "        </td>\n",
       "        <td>SUCCEEDED</td>\n",
       "        <td>Jan 14, 2020 02:12:53.994 PM</td>\n",
       "        <td>Jan 14, 2020 02:19:15.787 PM</td>\n",
       "    </tr>\n",
       "\n",
       "        </tbody>\n",
       "    </table>\n"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "execution_count": 69,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "my_attached_workflow.list_executions(html=True)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Use [list_workflows](https://aws-step-functions-data-science-sdk.readthedocs.io/en/latest/workflow.html#stepfunctions.workflow.Workflow.list_workflows) to list all workflows in your AWS account."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 70,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "data": {
      "text/html": [
       "\n",
       "    <style>\n",
       "        \n",
       "    .table-widget {\n",
       "        width: 100%;\n",
       "        font-size: 14px;\n",
       "        line-height: 28px;\n",
       "        color: #545b64;\n",
       "        border-spacing: 0;\n",
       "        background-color: #fff;\n",
       "        border-color: grey;\n",
       "        background: #fafafa;\n",
       "    }\n",
       "\n",
       "    .table-widget thead th {\n",
       "        text-align: left !important;\n",
       "        color: #879596;\n",
       "        padding: 0.3em 2em;\n",
       "        border-bottom: 1px solid #eaeded;\n",
       "        min-height: 4rem;\n",
       "        line-height: 28px;\n",
       "    }\n",
       "\n",
       "    .table-widget thead th:first-of-type {\n",
       "    }\n",
       "\n",
       "    .table-widget td {\n",
       "        overflow-wrap: break-word;\n",
       "        padding: 0.4em 2em;\n",
       "        line-height: 28px;\n",
       "        text-align: left !important;\n",
       "        background: #fff;\n",
       "        border-bottom: 1px solid #eaeded;\n",
       "        border-top: 1px solid transparent;\n",
       "    }\n",
       "\n",
       "    .table-widget td:before {\n",
       "        content: \"\";\n",
       "        height: 3rem;\n",
       "    }\n",
       "\n",
       "    a {\n",
       "        cursor: pointer;\n",
       "        text-decoration: none !important;\n",
       "        color: #007dbc;\n",
       "    }\n",
       "\n",
       "    a:hover {\n",
       "        text-decoration: underline !important;\n",
       "    }\n",
       "\n",
       "    a.disabled {\n",
       "        color: black;\n",
       "        cursor: default;\n",
       "        pointer-events: none;\n",
       "    }\n",
       "\n",
       "    .hide {\n",
       "        display: none;\n",
       "    }\n",
       "\n",
       "    pre {\n",
       "        white-space: pre-wrap;\n",
       "    }\n",
       "\n",
       "        \n",
       "    * {\n",
       "        box-sizing: border-box;\n",
       "    }\n",
       "\n",
       "    .table-widget {\n",
       "        min-width: 100%;\n",
       "        font-size: 14px;\n",
       "        line-height: 28px;\n",
       "        color: #545b64;\n",
       "        border-spacing: 0;\n",
       "        background-color: #fff;\n",
       "        border-color: grey;\n",
       "        background: #fafafa;\n",
       "    }\n",
       "\n",
       "    .table-widget thead th {\n",
       "        text-align: left !important;\n",
       "        color: #879596;\n",
       "        padding: 0.3em 2em;\n",
       "        border-bottom: 1px solid #eaeded;\n",
       "        min-height: 4rem;\n",
       "        line-height: 28px;\n",
       "    }\n",
       "\n",
       "    .table-widget td {\n",
       "        /* padding: 24px 18px; */\n",
       "        padding: 0.4em 2em;\n",
       "        line-height: 28px;\n",
       "        text-align: left !important;\n",
       "        background: #fff;\n",
       "        border-bottom: 1px solid #eaeded;\n",
       "        border-top: 1px solid transparent;\n",
       "    }\n",
       "\n",
       "    .table-widget td:before {\n",
       "        content: \"\";\n",
       "        height: 3rem;\n",
       "    }\n",
       "\n",
       "    .table-widget .clickable-cell {\n",
       "        cursor: pointer;\n",
       "    }\n",
       "\n",
       "    .hide {\n",
       "        display: none;\n",
       "    }\n",
       "\n",
       "    .triangle-right {\n",
       "        width: 0;\n",
       "        height: 0;\n",
       "        border-top: 5px solid transparent;\n",
       "        border-left: 8px solid #545b64;\n",
       "        border-bottom: 5px solid transparent;\n",
       "        margin-right: 5px;\n",
       "    }\n",
       "\n",
       "    a.awsui {\n",
       "        text-decoration: none !important;\n",
       "        color: #007dbc;\n",
       "    }\n",
       "\n",
       "    a.awsui:hover {\n",
       "        text-decoration: underline !important;\n",
       "    }\n",
       "\n",
       "    </style>\n",
       "    <table class=\"table-widget\">\n",
       "        <thead>\n",
       "            <tr>\n",
       "                <th>Name</th>\n",
       "                <th>Creation Date</th>\n",
       "            </tr>\n",
       "        </thead>\n",
       "        <tbody>\n",
       "            \n",
       "    <tr class=\"awsui-table-row\">\n",
       "        <td>\n",
       "            <a href=\"https://console.aws.amazon.com/states/home?region=us-east-1#/statemachines/view/arn:aws:states:us-east-1:806570384721:stateMachine:GlueJobStateMachine-new\" target=\"_blank\" class=\"awsui\">GlueJobStateMachine-new</a>\n",
       "        </td>\n",
       "        <td>Dec 12, 2019 04:51:12.357 AM</td>\n",
       "    </tr>\n",
       "\n",
       "\n",
       "    <tr class=\"awsui-table-row\">\n",
       "        <td>\n",
       "            <a href=\"https://console.aws.amazon.com/states/home?region=us-east-1#/statemachines/view/arn:aws:states:us-east-1:806570384721:stateMachine:MyTrainTransformDeploy_v1\" target=\"_blank\" class=\"awsui\">MyTrainTransformDeploy_v1</a>\n",
       "        </td>\n",
       "        <td>Jan 14, 2020 02:12:45.018 PM</td>\n",
       "    </tr>\n",
       "\n",
       "\n",
       "    <tr class=\"awsui-table-row\">\n",
       "        <td>\n",
       "            <a href=\"https://console.aws.amazon.com/states/home?region=us-east-1#/statemachines/view/arn:aws:states:us-east-1:806570384721:stateMachine:MyWorkflow_Simple\" target=\"_blank\" class=\"awsui\">MyWorkflow_Simple</a>\n",
       "        </td>\n",
       "        <td>Jan 14, 2020 01:44:06.833 PM</td>\n",
       "    </tr>\n",
       "\n",
       "\n",
       "    <tr class=\"awsui-table-row\">\n",
       "        <td>\n",
       "            <a href=\"https://console.aws.amazon.com/states/home?region=us-east-1#/statemachines/view/arn:aws:states:us-east-1:806570384721:stateMachine:MyWorkflow_v2\" target=\"_blank\" class=\"awsui\">MyWorkflow_v2</a>\n",
       "        </td>\n",
       "        <td>Jan 14, 2020 01:57:21.434 PM</td>\n",
       "    </tr>\n",
       "\n",
       "\n",
       "    <tr class=\"awsui-table-row\">\n",
       "        <td>\n",
       "            <a href=\"https://console.aws.amazon.com/states/home?region=us-east-1#/statemachines/view/arn:aws:states:us-east-1:806570384721:stateMachine:MyWorkflow_v3\" target=\"_blank\" class=\"awsui\">MyWorkflow_v3</a>\n",
       "        </td>\n",
       "        <td>Jan 14, 2020 02:03:09.829 PM</td>\n",
       "    </tr>\n",
       "\n",
       "\n",
       "    <tr class=\"awsui-table-row\">\n",
       "        <td>\n",
       "            <a href=\"https://console.aws.amazon.com/states/home?region=us-east-1#/statemachines/view/arn:aws:states:us-east-1:806570384721:stateMachine:training-pipeline-2019-12-27-13-01-11\" target=\"_blank\" class=\"awsui\">training-pipeline-2019-12-27-13-01-11</a>\n",
       "        </td>\n",
       "        <td>Dec 27, 2019 01:02:49.455 PM</td>\n",
       "    </tr>\n",
       "\n",
       "\n",
       "    <tr class=\"awsui-table-row\">\n",
       "        <td>\n",
       "            <a href=\"https://console.aws.amazon.com/states/home?region=us-east-1#/statemachines/view/arn:aws:states:us-east-1:806570384721:stateMachine:training-pipeline-2019-12-27-19-55-38\" target=\"_blank\" class=\"awsui\">training-pipeline-2019-12-27-19-55-38</a>\n",
       "        </td>\n",
       "        <td>Dec 27, 2019 07:56:55.980 PM</td>\n",
       "    </tr>\n",
       "\n",
       "\n",
       "    <tr class=\"awsui-table-row\">\n",
       "        <td>\n",
       "            <a href=\"https://console.aws.amazon.com/states/home?region=us-east-1#/statemachines/view/arn:aws:states:us-east-1:806570384721:stateMachine:training-pipeline-2019-12-27-19-59-20\" target=\"_blank\" class=\"awsui\">training-pipeline-2019-12-27-19-59-20</a>\n",
       "        </td>\n",
       "        <td>Dec 27, 2019 07:59:35.097 PM</td>\n",
       "    </tr>\n",
       "\n",
       "        </tbody>\n",
       "    </table>\n"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "execution_count": 70,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "Workflow.list_workflows(html=True)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Validate the model for use"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Finally, the customer can now validate the model for use. They can obtain the endpoint from the client library using the result from previous operations, and generate classifications from the trained model using that endpoint."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {},
   "outputs": [],
   "source": [
    "runtime_client = boto3.client('runtime.sagemaker', region_name=region)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Start with a single prediction."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {},
   "outputs": [],
   "source": [
    "!head -1 abalone.test > abalone.single.test"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "7 1:3 2:0.365 3:0.27 4:0.085 5:0.196 6:0.0825 7:0.0375 8:0.06\r\n"
     ]
    }
   ],
   "source": [
    "!cat abalone.single.test"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "regression-8fa819d436da11ea97286d708cc45e75\n"
     ]
    }
   ],
   "source": [
    "print(endpoint_name)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Label:  7 \n",
      "Prediction:  7\n",
      "CPU times: user 12.8 ms, sys: 6 µs, total: 12.8 ms\n",
      "Wall time: 166 ms\n"
     ]
    }
   ],
   "source": [
    "%%time\n",
    "import json\n",
    "from itertools import islice\n",
    "import math\n",
    "import struct\n",
    "\n",
    "file_name = 'abalone.single.test' #customize to your test file\n",
    "with open(file_name, 'r') as f:\n",
    "    payload = f.read().strip()\n",
    "response = runtime_client.invoke_endpoint(EndpointName=endpoint_name, \n",
    "                                   ContentType='text/x-libsvm', \n",
    "                                   Body=payload)\n",
    "result = response['Body'].read()\n",
    "result = result.decode(\"utf-8\")\n",
    "result = result.split(',')\n",
    "result = [math.ceil(float(i)) for i in result]\n",
    "label = payload.strip(' ').split()[0]\n",
    "print ('Label: ',label,'\\nPrediction: ', result[0])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "OK, a single prediction works. Let's do a whole batch to see how good is the predictions accuracy"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 37,
   "metadata": {},
   "outputs": [],
   "source": [
    "import sys\n",
    "import math\n",
    "def do_predict(data, endpoint_name, content_type):\n",
    "    payload = '\\n'.join(data)\n",
    "    response = runtime_client.invoke_endpoint(EndpointName=endpoint_name, \n",
    "                                   ContentType=content_type, \n",
    "                                   Body=payload)\n",
    "    result = response['Body'].read()\n",
    "    result = result.decode(\"utf-8\")\n",
    "    result = result.split(',')\n",
    "    preds = [float((num)) for num in result]\n",
    "    preds = [math.ceil(num) for num in preds]\n",
    "    return preds\n",
    "\n",
    "def batch_predict(data, batch_size, endpoint_name, content_type):\n",
    "    items = len(data)\n",
    "    arrs = []\n",
    "    \n",
    "    for offset in range(0, items, batch_size):\n",
    "        if offset+batch_size < items:\n",
    "            results = do_predict(data[offset:(offset+batch_size)], endpoint_name, content_type)\n",
    "            arrs.extend(results)\n",
    "        else:\n",
    "            arrs.extend(do_predict(data[offset:items], endpoint_name, content_type))\n",
    "        sys.stdout.write('.')\n",
    "    return(arrs)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The following helps us calculate the Median Absolute Percent Error (MdAPE) on the batch dataset."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 71,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      ".......\n",
      " Median Absolute Percent Error (MdAPE) =  0.125\n"
     ]
    }
   ],
   "source": [
    "import json\n",
    "import numpy as np\n",
    "\n",
    "with open(FILE_TEST, 'r') as f:\n",
    "    payload = f.read().strip()\n",
    "\n",
    "labels = [int(line.split(' ')[0]) for line in payload.split('\\n')]\n",
    "test_data = [line for line in payload.split('\\n')]\n",
    "preds = batch_predict(test_data, 100, endpoint_name, 'text/x-libsvm')\n",
    "\n",
    "print('\\n Median Absolute Percent Error (MdAPE) = ', np.median(np.abs(np.array(labels) - np.array(preds)) / np.array(labels)))\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 41,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      ".[7]\n",
      "[7]\n",
      "\n",
      " Median Absolute Percent Error (MdAPE) =  0.0\n"
     ]
    }
   ],
   "source": [
    "file_name = 'abalone.single.test' #customize to your test file\n",
    "\n",
    "import json\n",
    "import numpy as np\n",
    "\n",
    "with open(file_name, 'r') as f:\n",
    "    payload = f.read().strip()\n",
    "\n",
    "labels = [int(line.split(' ')[0]) for line in payload.split('\\n')]\n",
    "test_data = [line for line in payload.split('\\n')]\n",
    "preds = batch_predict(test_data, 100, endpoint_name, 'text/x-libsvm')\n",
    "print(preds)\n",
    "print(labels)\n",
    "print('\\n Median Absolute Percent Error (MdAPE) = ', np.median(np.abs(np.array(labels) - np.array(preds)) / np.array(labels)))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Delete Endpoint"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Once you are done using the endpoint, you can use the following to delete it."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "client.delete_endpoint(EndpointName=endpoint_name)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "conda_python3",
   "language": "python",
   "name": "conda_python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.5"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
